import React, {Component, Fragment} from 'react';
import {StyleSheet, Text, View, Button} from 'react-native';
import schema from 'async-validator';
import ComponentFactory from './ComponentFactory';
function keyValueBy(array, key, value) {
  return Object.assign(
    {},
    ...array.map((ele) => {
      return {
        [ele[key]]: ele[value],
      };
    }),
  );
}

export default class Form extends Component {
  constructor(props) {
    super(props);
    const {defaultForm = {}} = props;
    this.state = {
      form: defaultForm,
      errors: [],
    };
  }

  getForm() {
    const {form} = this.state;
    return form || {};
  }
  getNativeObject(key) {
    const {form} = this.state;
    return form[`_${key}`];
  }
  getValue(key) {
    const {form} = this.state;
    return form[key];
  }
  setValue(key, value) {
    const {form, errors} = this.state;
    if (form[key] === value) {
      return;
    }
    this.setState(
      {
        form: {
          ...form,
          [key]: value,
        },
      },
      () => {
        const item = this.getItem(key);
        if (item && item.onValueChange) {
          item.onValueChange(this, value);
        }
        // onValueChange
        if (errors && errors.length) {
          this.valid()
            .then(() => {
              this.setState({
                errors: [],
              });
            })
            .catch(({errors, fields}) => {
              this.setState({
                errors,
              });
            });
        }
      },
    );
  }
  getItem(key) {
    const formItems = this.getFormItems();
    const item = formItems.find((ele) => ele.value === key);
    return item;
  }
  getDisabled(key) {
    const item = this.getItem(key);
    if (!item) {
      return false;
    }
    const {disabled} = item;
    if (!disabled) {
      return false;
    }
    if (typeof disabled === 'function') {
      return !!disabled(this, this.getForm());
    }
    return false;
  }

  getMessages(key) {
    const {errors = []} = this.state;
    const messages = [];
    const item = this.getItem(key);
    if (item.messages) {
      messages.push(...item.messages);
    }
    const error = errors.find((ele) => ele.field === key);
    if (error) {
      messages.push(error && error.message);
    }
    return messages;
  }
  getFormItems() {
    const {formItems = []} = this.props;
    const array = [];
    function getItems(items) {
      for (const item of items) {
        if (item.childrens) {
          getItems(item.childrens);
        } else {
          array.push(item);
        }
      }
    }
    getItems(formItems);
    return array;
  }
  valid() {
    const formItems = this.getFormItems();
    const {form} = this.state;
    const descriptor = keyValueBy(
      formItems.filter((ele) => ele.rule),
      'value',
      'rule',
    );
    var validator = new schema(descriptor);
    return validator.validate(form);
  }

  doValid() {
    const {onSubmit} = this.props;
    const {form} = this.state;
    this.valid()
      .then(() => {
        this.setState({
          errors: [],
        });
        onSubmit(form);
      })
      .catch(({errors, fields}) => {
        return this.handleErrors(errors, fields);
      });
  }

  handleErrors(errors, fields) {
    this.setState({
      errors,
    });
    // alert(JSON.stringify(errors));
  }

  render() {
    const formItems = this.getFormItems();
    const {formItems: items} = this.props;
    const {form} = this.state;
    return (
      <View style={styles.container}>
        {items.map((ele) => {
          const {childrens} = ele;
          if (childrens) {
            const Group = ComponentFactory.getComponent(this, ele);
            return (
              <Fragment key={ele.value}>
                {React.cloneElement(Group, {
                  children: childrens.map((children) => (
                    <Fragment key={children.value}>
                      {ComponentFactory.getComponent(this, children)}
                    </Fragment>
                  )),
                })}
              </Fragment>
            );
          }
          return (
            <Fragment key={ele.value}>
              {ComponentFactory.getComponent(this, ele)}
            </Fragment>
          );
        })}
        <Button title="Submit" onPress={this.doValid.bind(this)} />
        <Text>{JSON.stringify(form)}</Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
});
